iT邦幫忙

2024 iThome 鐵人賽

DAY 28
1

https://ithelp.ithome.com.tw/upload/images/20240927/20117461aJq0CRbpxM.jpg

簡介

在現代的 Web 應用開發中,有效管理全局狀態是一個關鍵挑戰。Nuxt3 作為一個強大的 Vue.js 框架,結合 Pinia 這個靈活的狀態管理庫,為開發者提供了一套完整的解決方案。本文將深入探討如何在 Nuxt3 中使用 Pinia 管理全局狀態,並整合其他先進的前端技術,如 Zod、Vee-Validate 和 VueUse,以構建一個健壯、高效的應用。

Pinia 在 Nuxt3 中的應用

步驟 1: 安裝必要的依賴

首先,我們需要安裝 Pinia 和其他相關的包:

bunx nuxi module add pinia
bunx nuxi module vee-validate
bunx nuxi module vueuse
bun add zod @vee-validate/zod @vueuse/core

步驟 2: 創建 Pinia Store

stores 目錄下創建一個新的 store 文件,例如 userStore.ts

import * as zod from 'zod';
import { defineStore, acceptHMRUpdate } from 'pinia';

export const userSchema = zod.object({
  id: zod.number(),
  name: zod.string(),
  email: zod.string().email(),
});

export type UserSchema = zod.infer<typeof userSchema>;

export const useBaseStore = defineStore('useBaseStore', () => {

  // state::
  const user = ref<UserSchema | null>(null);

  // methods::
  const fetchUser = async (): Promise<void> => {
    const response = await $fetch('/api/user', {
      method: 'GET',
    });
    const validator = userSchema.safeParse(response);
    if (!validator.success) {
      throw new TypeError('validator error');
    }
    user.value = validator.data;
  };

  const logout = (): void => {
    user.value = null;
  };

  return {
    // state::
    user,
    // methods::
    fetchUser,
    logout,
  }
})

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useBaseStore, import.meta.hot));
}

步驟 3: 在組件中使用 Store

創建一個新的組件 UserProfile.vue

<template>
  <div v-if="user">
    <h2>Welcome, {{ user.name }}!</h2>
    <p>Email: {{ user.email }}</p>
    <button @click="logout">Logout</button>
  </div>
  <div v-else>
    <p>Please log in</p>
  </div>
</template>

<script setup lang="ts">
import { useUserStore } from '~/stores/userStore'
import { storeToRefs } from 'pinia'

const userStore = useUserStore()
const { user } = storeToRefs(userStore)
const { logout } = userStore

onMounted(async () => {
  await userStore.fetchUser()
})
</script>

步驟 4: 處理客戶端存儲

為了處理客戶端存儲,我們可以使用 VueUse 的 useLocalStorage 和 Nuxt3 的 useNuxtApp

import { defineStore } from 'pinia'
import { useLocalStorage } from '@vueuse/core'

export const useUserStore = defineStore('user', () => {
  const nuxtApp = useNuxtApp()
  
  const user = ref(null)
  
  if (process.client) {
    const storedUser = useLocalStorage('user', null)
    watch(storedUser, (newValue) => {
      user.value = newValue
    })
  }

  async function fetchUser() {
    const response = await nuxtApp.$fetch('/api/user')
    user.value = response
    if (process.client) {
      localStorage.setItem('user', JSON.stringify(response))
    }
  }

  return { user, fetchUser }
})

步驟 5: 解決 Hydration 問題

為了解決可能出現的 hydration 問題,我們可以使用 Nuxt3 的 <ClientOnly> 組件:

<template>
  <ClientOnly>
    <div v-if="user">
      <h2>Welcome, {{ user.name }}!</h2>
      <p>Email: {{ user.email }}</p>
    </div>
    <template #fallback>
      <p>Loading user data...</p>
    </template>
  </ClientOnly>
</template>

結論

在 Nuxt3 中使用 Pinia 管理全局狀態不僅提高了開發效率,還增強了應用的可維護性和可擴展性。通過整合 Zod 進行數據驗證、Vee-Validate 處理表單驗證,以及利用 VueUse 的 useLocalStorage 處理客戶端存儲,我們構建了一個強大而靈活的狀態管理系統。

需要特別注意的是在服務器端渲染(SSR)環境中處理客戶端特定的操作,如本地存儲。使用 Nuxt3 的 <ClientOnly> 組件和條件性的代碼執行可以有效解決 hydration 問題。

最後,使用 Nuxt 提供的 $fetch 方法進行 API 請求,進一步統一了我們的數據獲取策略。這種整合方法不僅簡化了開發流程,還提高了代碼的一致性和可讀性。

通過實施這些最佳實踐,開發者可以充分利用 Nuxt3 和 Pinia 的優勢,構建出高效、可靠且易於維護的現代 Web 應用。


上一篇
Day 27: 初探 Nuxt3:如何利用 Nuxt3 與 TypeScript 打造伺服器端渲染應用
下一篇
Day 29: Nuxt3 中的路由管理以及 Middleware:如何結合 TypeScript 實現靈活的路由系統
系列文
Vue 和 TypeScript 的最佳實踐:成為前端工程師的進階利器30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言